package auth.config;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import auth.controller.AuthController;

import java.awt.image.BufferedImage;
import java.net.InetAddress;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;

/**
 * Auth服务预热配置
 * 用于服务启动时预热关键组件，减少首次请求的响应时间
 */
@Component
public class PrewarmConfig implements ApplicationRunner {
    
    private static final Logger logger = LoggerFactory.getLogger(PrewarmConfig.class);
    
    @Autowired
    private ApplicationContext applicationContext;
    
    @Autowired
    private StringRedisTemplate redisTemplate;
    
    @Autowired
    private RestTemplate restTemplate;
    
    @Autowired(required = false)
    private AuthController authController;
    
    @Value("${server.port:8080}")
    private String serverPort;
    
    @Override
    public void run(ApplicationArguments args) {
        try {
            logger.info("开始预热Auth服务...");
            
            // 获取主机名和IP
            String hostName = InetAddress.getLocalHost().getHostName();
            String hostAddress = InetAddress.getLocalHost().getHostAddress();
            
            logger.info("预热Auth服务 - 主机名: {}, IP: {}, 端口: {}", hostName, hostAddress, serverPort);
            
            // 1. 预热Spring容器中的Bean
            prewarmSpringBeans();
            
            // 2. 预热Redis连接
            prewarmRedisConnection();
            
            // 3. 预热内部接口
            prewarmInternalEndpoints();
            
            // 4. 预热验证码生成
            prewarmCaptchaGeneration();
            
            logger.info("Auth服务预热完成");
        } catch (Exception e) {
            logger.error("Auth服务预热过程中发生错误", e);
        }
    }
    
    /**
     * 预热Spring容器中的关键Bean
     */
    private void prewarmSpringBeans() {
        logger.info("预热Spring容器中的关键Bean...");
        long startTime = System.currentTimeMillis();
        
        // 获取所有Bean的名称并记录数量
        String[] beanNames = applicationContext.getBeanDefinitionNames();
        logger.info("Spring容器中共有 {} 个Bean", beanNames.length);
        
        // 预热关键Bean（可以根据需要添加更多）
        String[] criticalBeans = {"userService", "jwtUtil", "stringRedisTemplate", "authController"};
        Arrays.stream(criticalBeans).forEach(beanName -> {
            try {
                if (applicationContext.containsBean(beanName)) {
                    Object bean = applicationContext.getBean(beanName);
                    logger.info("成功预热Bean: {}, 类型: {}", beanName, bean.getClass().getName());
                }
            } catch (Exception e) {
                logger.warn("预热Bean {} 失败: {}", beanName, e.getMessage());
            }
        });
        
        long duration = System.currentTimeMillis() - startTime;
        logger.info("Spring容器Bean预热完成，耗时: {} ms", duration);
    }
    
    /**
     * 预热验证码生成功能
     */
    private void prewarmCaptchaGeneration() {
        logger.info("预热验证码生成功能...");
        long startTime = System.currentTimeMillis();
        
        try {
            // 直接通过反射调用AuthController中的私有方法进行预热
            if (authController != null) {
                // 预热生成验证码文本
                java.lang.reflect.Method generateCaptchaTextMethod = AuthController.class.getDeclaredMethod("generateCaptchaText", int.class);
                generateCaptchaTextMethod.setAccessible(true);
                String captchaText = (String) generateCaptchaTextMethod.invoke(authController, 4);
                
                // 预热生成验证码图片
                java.lang.reflect.Method createCaptchaImageMethod = AuthController.class.getDeclaredMethod("createCaptchaImage", String.class, int.class, int.class);
                createCaptchaImageMethod.setAccessible(true);
                BufferedImage image = (BufferedImage) createCaptchaImageMethod.invoke(authController, captchaText, 120, 40);
                
                // 预热Base64转换
                java.lang.reflect.Method convertImageToBase64Method = AuthController.class.getDeclaredMethod("convertImageToBase64", BufferedImage.class);
                convertImageToBase64Method.setAccessible(true);
                convertImageToBase64Method.invoke(authController, image);
                
                logger.info("成功预热验证码生成方法");
            } else {
                logger.warn("AuthController未注入，跳过验证码生成方法预热");
            }
            
            long duration = System.currentTimeMillis() - startTime;
            logger.info("验证码生成功能预热完成，耗时: {} ms", duration);
        } catch (Exception e) {
            logger.warn("验证码生成功能预热失败: {}", e.getMessage());
        }
    }
    
    /**
     * 预热内部接口
     */
    private void prewarmInternalEndpoints() {
        logger.info("预热内部接口...");
        long startTime = System.currentTimeMillis();
        
        try {
            // 预热健康检查接口
            String healthUrl = "http://localhost:" + serverPort + "/actuator/health";
            restTemplate.getForObject(healthUrl, String.class);
            logger.info("成功预热健康检查接口: {}", healthUrl);
            
            // 预热验证码接口
            String captchaUrl = "http://localhost:" + serverPort + "/auth/captcha";
            restTemplate.getForObject(captchaUrl, String.class);
            logger.info("成功预热验证码接口: {}", captchaUrl);
            
            long duration = System.currentTimeMillis() - startTime;
            logger.info("内部接口预热完成，耗时: {} ms", duration);
        } catch (Exception e) {
            logger.warn("内部接口预热失败: {}", e.getMessage());
        }
    }
    
    /**
     * 预热Redis连接
     */
    private void prewarmRedisConnection() {
        logger.info("预热Redis连接...");
        long startTime = System.currentTimeMillis();
        
        try {
            // 执行一个简单的Redis操作来预热连接
            String key = "prewarm:auth:test";
            redisTemplate.hasKey(key);
            redisTemplate.opsForValue().set(key, "prewarming", 10, TimeUnit.SECONDS);
            redisTemplate.opsForValue().get(key);
            redisTemplate.delete(key);
            
            logger.info("成功预热Redis连接");
            
            long duration = System.currentTimeMillis() - startTime;
            logger.info("Redis连接预热完成，耗时: {} ms", duration);
        } catch (Exception e) {
            logger.warn("Redis连接预热失败: {}", e.getMessage());
        }
    }
} 